/*
 * @description: 
 * @Author: Islands
 * @Date: 2023-06-21 09:29:36
 * @LastEditTime: 2024-03-26 10:59:52
 */
import { defineStore } from 'pinia';
import { ElMessage } from 'element-plus'
import { resetRouter } from '@/router/index';
import { IUserInfo, IRoutes, IMeta, ILoginData } from '@/axios/login/types.d';
import { getUserInfoApi, getRoutesApi, loginApi } from '@/axios/login/index';

import Layout from '@/layout/index.vue';
const modules = import.meta.glob('/src/views/**/**.vue');

import menus from '@/mock/routes/index.json';
export const useAuthStore = defineStore('authorization', {
    state: () => ({
        /**
         * 用户信息
         */
        userInfo: {
            authorities: [],
            roles: [],
        } as IUserInfo,
        /**
         * 路由
         */
        routes: [] as Array<IRoutes<IMeta>>,
        /**
         * 菜单
         */
        menus: [] as Array<any>,
    }),
    actions: {
        login(loginData: ILoginData) {
            return new Promise<void>((resolve, reject) => {
                loginApi(loginData)
                    .then((data: any) => {
                        const { token_type, access_token } = data;
                        localStorage.setItem("accessToken", token_type + " " + access_token);
                        ElMessage.success("登录成功");
                        resolve();
                    })
                    .catch((error) => {
                        ElMessage.success("登录失败");
                        reject(error);
                    });
            });
        },
        /**
         *  获取信息(用户昵称、头像、角色集合、权限集合)
         *  object.assign() 主要用于对象合并，将源对象中的属性复制到目标对象中，他将返回目标对象。
         * @returns 
         */
        getUserInfo() {
            return new Promise<IUserInfo>((resolve, reject) => {
                getUserInfoApi()
                    .then((data: any) => {
                        Object.assign(this.userInfo, { ...data });
                        resolve(data);
                    })
                    .catch((error: any) => {
                        reject(error);
                    })
            })
        },
        /**
         * 获取路由
         * @param roles 
         * @returns 
         */
        getRoutes(roles: Array<string>) {
            return new Promise<Array<IRoutes<IMeta>>>((resolve, reject) => {
                getRoutesApi()
                    .then((data: any) => {
                        // 根据角色获取有访问权限的路由
                        const accessedRoutes = filterAsyncRoutes(data, roles);
                        Object.assign(this.routes, { ...accessedRoutes });
                        resolve(accessedRoutes);
                    })
                    .catch((error: any) => {
                        reject(error);
                    })
            })
        },
        /***
         * 移除令牌并重置路由
         */
        resetToken() {
            return new Promise<void>((resolve) => {
                localStorage.setItem("accessToken", "");
                resetRouter();
                resolve();
            });
        }


    },
    getters: {
        /**
         * 解决单个首页，只加载一个首页问题/且多个首页无效
         * @param state 
         * @returns 
         */
        getMenu: (state) => {
            menus.filter((_item: any) => {
                if (_item.path == '/home' && _item.children.length == 1) {
                    _item.children.filter((_i: any) => {
                        state.menus.push(_i)
                    })
                } else {
                    state.menus.push(_item);
                }

            })
            return state.menus;
        },

    },
    // persist: {
    //     // 在这里进行自定义配置
    //     storage: localStorage,
    //     paths: ['token']
    // },
});


/**
 * 递归过滤有权限的异步(动态)路由
 * @param routes    接口返回的异步(动态)路由
 * @param roles 用户角色集合
 * @returns 返回用户有权限的异步(动态)路由
 */
function filterAsyncRoutes(routes: Array<IRoutes<IMeta>>, roles: Array<string>) {
    const asyncRoutes: Array<IRoutes<IMeta>> = [];
    routes.forEach((route: IRoutes<IMeta>) => {
        const tmpRoute = { ...route }; // ES6扩展运算符复制新对象
        if (!route.name) {
            tmpRoute.name = route.path;
        }
        // 判断用户(角色)是否有该路由的访问权限
        if (hasPermission(roles, tmpRoute)) {
            if (tmpRoute.component?.toString() == "Layout" || tmpRoute.component === undefined) {
                tmpRoute.component = Layout;
            } else {
                const component = modules[`/src/views/${tmpRoute.component}/index.vue`];
                if (component) {
                    tmpRoute.component = component;
                } else {
                    tmpRoute.component = modules[`/src/views/404/index.vue`];
                }
            }

            if (tmpRoute.children) {
                tmpRoute.children = filterAsyncRoutes(tmpRoute.children, roles);
            }

            asyncRoutes.push(tmpRoute);
        }
    });
    return asyncRoutes;
}


/**
 * 使用meta.role确定当前用户是否具有权限
 *
 * @param roles 用户角色集合
 * @param route 路由
 * @returns
 */
const hasPermission = (roles: string[], route: IRoutes<IMeta>) => {
    if (route.meta && route.meta.roles) {
        // 角色【超级管理员】拥有所有权限，忽略校验
        if (roles.includes("ROOT")) {
            return true;
        }
        return roles.some((role) => {
            if (route.meta?.roles) {
                return route.meta.roles.includes(role);
            }
        });
    }
    return false;
};